/**************************************************************************//**
 * @file     SDGlue.c
 * @version  V1.00
 * @brief    SD glue functions for FATFS
 *
 * 备注：此例程出现过中断无法退出，原因未知
*****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "NuMicro.h"
#include "diskio.h"     /* FatFs lower layer API */
#include "ff.h"     /* FatFs lower layer API */
#include "os_obj.h"

FATFS  _FatfsVolSd0;
FATFS  _FatfsVolSd1;

static TCHAR  _Path[3];

int32_t SDH_Open_Disk(SDH_T *sdh, uint32_t u32CardDetSrc)
{
    SDH_Open(sdh, u32CardDetSrc);
    if (SDH_Probe(sdh))
    {
        return Fail;
    }

    _Path[1] = ':';
    _Path[2] = 0;
    if (sdh == SDH0)
    {
        _Path[0] = '0';
        f_mount(&_FatfsVolSd0, _Path, 1);
    }
    else
    {
        _Path[0] = '1';
        f_mount(&_FatfsVolSd1, _Path, 1);
    }
    return Successful;
}

void SDH_Close_Disk(SDH_T *sdh)
{
    if (sdh == SDH0)
    {
        memset(&SD0, 0, sizeof(SDH_INFO_T));
        f_mount(NULL, _Path, 1);
        memset(&_FatfsVolSd0, 0, sizeof(FATFS));
    }
    else
    {
        memset(&SD1, 0, sizeof(SDH_INFO_T));
        f_mount(NULL, _Path, 1);
        memset(&_FatfsVolSd1, 0, sizeof(FATFS));
    }
}

/*****************************************************************************//*!
* @brief   sd hal task.
* @param   none
* @return  none
* @ Pass/ Fail criteria: none
*****************************************************************************/
void sd_event_task(void const *argument)
{
	uint32_t isr;
	
	osEvent event;
	osDelay(INT32_MAX);
	
	while(1)
	{
		event = osSignalWait(0, 100000);
		
		// 事件接收状态
		if(event.status == osEventSignal)
		{
			// SD0 event
			if(event.value.signals & 0x01)
			{
				//----- SD interrupt status
				// it is work to delay 50 times for SD_CLK = 200KHz
				{
					int volatile i;         // delay 30 fail, 50 OK
					for (i=0; i<0x500; i++);  // delay to make sure got updated value from REG_SDISR.
					isr = SDH0->INTSTS;
				}

				if (isr & SDH_INTSTS_CDSTS_Msk)
				{
					printf("\n***** card remove !\n");
					SD0.IsCardInsert = FALSE;   // SDISR_CD_Card = 1 means card remove for GPIO mode
					memset(&SD0, 0, sizeof(SDH_INFO_T));
					
				}
				else
				{
					printf("***** card insert !\n");
					SDH_Open(SDH0, CardDetect_From_GPIO);
					SDH_Probe(SDH0);
					
				}

				SDH0->INTSTS = SDH_INTSTS_CDIF_Msk;
				osSignalClear(os_obj.tid_sd_task, 0x01);
			}
			
			// SD1事件
			if(event.value.signals & 0x02)
			{
				//----- SD interrupt status
				// it is work to delay 50 times for SD_CLK = 200KHz
				{
					int volatile i;         // delay 30 fail, 50 OK
					for (i=0; i<0x500; i++);  // delay to make sure got updated value from REG_SDISR.
					isr = SDH1->INTSTS;
				}

				if (isr & SDH_INTSTS_CDSTS_Msk)
				{
					printf("\n***** card remove ! 0x%x\n", isr);
					SD1.IsCardInsert = FALSE;   // SDISR_CD_Card = 1 means card remove for GPIO mode
					memset(&SD1, 0, sizeof(SDH_INFO_T));
				}
				else
				{
					printf("***** card insert !\n");
					SDH_Open(SDH1, CardDetect_From_GPIO);
					SDH_Probe(SDH1);
				}

				SDH1->INTSTS = SDH_INTSTS_CDIF_Msk;
				osSignalClear(os_obj.tid_sd_task, 0x02);
			}
		}
	}
}

void SDH0_IRQHandler(void)
{
    unsigned int volatile isr;
    unsigned int volatile ier;

    // FMI data abort interrupt
    if (SDH0->GINTSTS & SDH_GINTSTS_DTAIF_Msk)
    {
        /* ResetAllEngine() */
        SDH0->GCTL |= SDH_GCTL_GCTLRST_Msk;
    }

    //----- SD interrupt status
    isr = SDH0->INTSTS;
    if (isr & SDH_INTSTS_BLKDIF_Msk)
    {
        // block down
        SD0.DataReadyFlag = TRUE;
        SDH0->INTSTS = SDH_INTSTS_BLKDIF_Msk;
    }

    if (isr & SDH_INTSTS_CDIF_Msk)   // card detect
    {
		osSignalSet(os_obj.tid_sd_task, 1);
		
        SDH0->INTSTS = SDH_INTSTS_CDIF_Msk;
    }

    // CRC error interrupt
    if (isr & SDH_INTSTS_CRCIF_Msk)
    {
        if (!(isr & SDH_INTSTS_CRC16_Msk))
        {
            //printf("***** ISR sdioIntHandler(): CRC_16 error !\n");
            // handle CRC error
        }
        else if (!(isr & SDH_INTSTS_CRC7_Msk))
        {
            if (!SD0.R3Flag)
            {
                //printf("***** ISR sdioIntHandler(): CRC_7 error !\n");
                // handle CRC error
            }
        }
        SDH0->INTSTS = SDH_INTSTS_CRCIF_Msk;      // clear interrupt flag
    }

    if (isr & SDH_INTSTS_DITOIF_Msk)
    {
        printf("***** ISR: data in timeout !\n");
        SDH0->INTSTS |= SDH_INTSTS_DITOIF_Msk;
    }

    // Response in timeout interrupt
    if (isr & SDH_INTSTS_RTOIF_Msk)
    {
        printf("***** ISR: response in timeout !\n");
        SDH0->INTSTS |= SDH_INTSTS_RTOIF_Msk;
    }
}


void SDH1_IRQHandler(void)
{
    unsigned int volatile isr;
    unsigned int volatile ier;

    // FMI data abort interrupt
    if (SDH1->GINTSTS & SDH_GINTSTS_DTAIF_Msk)
    {
        /* ResetAllEngine() */
        SDH1->GCTL |= SDH_GCTL_GCTLRST_Msk;
    }

    //----- SD interrupt status
    isr = SDH1->INTSTS;
    if (isr & SDH_INTSTS_BLKDIF_Msk)
    {
        // block down
        SD1.DataReadyFlag = TRUE;
        SDH1->INTSTS = SDH_INTSTS_BLKDIF_Msk;
    }

    if (isr & SDH_INTSTS_CDIF_Msk)   // card detect
    {
		osSignalSet(os_obj.tid_sd_task, 2);
		
        SDH1->INTSTS = SDH_INTSTS_CDIF_Msk;
    }

    // CRC error interrupt
    if (isr & SDH_INTSTS_CRCIF_Msk)
    {
        if (!(isr & SDH_INTSTS_CRC16_Msk))
        {
            //printf("***** ISR sdioIntHandler(): CRC_16 error !\n");
            // handle CRC error
        }
        else if (!(isr & SDH_INTSTS_CRC7_Msk))
        {
            if (!SD1.R3Flag)
            {
                //printf("***** ISR sdioIntHandler(): CRC_7 error !\n");
                // handle CRC error
            }
        }
        SDH1->INTSTS = SDH_INTSTS_CRCIF_Msk;      // clear interrupt flag
    }

    if (isr & SDH_INTSTS_DITOIF_Msk)
    {
        printf("***** ISR: data in timeout !\n");
        SDH1->INTSTS |= SDH_INTSTS_DITOIF_Msk;
    }

    // Response in timeout interrupt
    if (isr & SDH_INTSTS_RTOIF_Msk)
    {
        printf("***** ISR: response in timeout !\n");
        SDH1->INTSTS |= SDH_INTSTS_RTOIF_Msk;
    }
}
